#include "common.h"
#include <Windows.h>


value python__string() {
return ConvPy2Neko(PyObject_Str(val_data(val_field(val_this(), val_id("pyPtr")))));
}

value python__compare(value obj) {
int result = PyObject_Compare(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(obj));
if(PyErr_Occurred()) failure(PyString_AsString(PyObject_Str(PyErr_Occurred())));
return alloc_int(result);
}

value python__add(value obj) {
return ConvPy2Neko(PyNumber_Add(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(obj)));
}

value python__radd(value obj) {
return ConvPy2Neko(PyNumber_Add(ConvNeko2Py(obj), val_data(val_field(val_this(), val_id("pyPtr")))));
}

value python__sub(value obj) {
return ConvPy2Neko(PyNumber_Subtract(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(obj)));
}

value python__rsub(value obj) {
return ConvPy2Neko(PyNumber_Subtract(ConvNeko2Py(obj), val_data(val_field(val_this(), val_id("pyPtr")))));
}

value python__mult(value obj) {
return ConvPy2Neko(PyNumber_Multiply(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(obj)));
}

value python__rmult(value obj) {
return ConvPy2Neko(PyNumber_Multiply(ConvNeko2Py(obj), val_data(val_field(val_this(), val_id("pyPtr")))));
}

value python__div(value obj) {
return ConvPy2Neko(PyNumber_Divide(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(obj)));
}

value python__rdiv(value obj) {
return ConvPy2Neko(PyNumber_Divide(ConvNeko2Py(obj), val_data(val_field(val_this(), val_id("pyPtr")))));
}

value python__mod(value obj) {
return ConvPy2Neko(PyNumber_Remainder(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(obj)));
}

value python__rmod(value obj) {
return ConvPy2Neko(PyNumber_Remainder(ConvNeko2Py(obj), val_data(val_field(val_this(), val_id("pyPtr")))));
}

value python__get(value key) {
return ConvPy2Neko(PyObject_GetItem(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(key)));
}

value python__set(value key, value obj) {
PyObject_SetItem(val_data(val_field(val_this(), val_id("pyPtr"))), ConvNeko2Py(key), ConvNeko2Py(obj));
return val_null;
}

value python_globals() {
PyObject *g = PyEval_GetGlobals();
if (!g) {
	PyObject *module = PyImport_AddModule("__main__");
	if (!module) {
		failure("Can't get __main__ module");
		return NULL;
		}
	g = PyModule_GetDict(module);
	}
if(!g) {
	PyErr_Print();
	failure("Can't get globals");
	return NULL;
	}
return ConvPy2Neko(g);
}

value python_locals() {
PyObject *l = PyEval_GetLocals();
if(!l) return python_globals();
return ConvPy2Neko(l);
}

value python_run(value str, bool eval) {
PyObject *d, *o, *m = PyImport_AddModule("__main__");
const char *s = val_string(str);
if (!m) {
	failure("Can't get __main__ module");
	return 0;
	}
d = PyModule_GetDict(m);
o = PyRun_StringFlags(s, eval ? Py_eval_input : Py_single_input, d, d, NULL);
if (!o) {
	PyErr_Print();
	return 0;
    }
return ConvPy2Neko(o);
}

DEFINE_ENTRY_POINT(python_main)

void python_main() {
pyProto = alloc_object(NULL);
//alloc_field(pyProto, val_id("__string"), alloc_function(python__string, 0, "python__string"));
alloc_field(pyProto, val_id("__compare"), alloc_function(python__compare, 1, "python__compare"));
alloc_field(pyProto, val_id("__add"), alloc_function(python__add, 1, "python__add"));
alloc_field(pyProto, val_id("__radd"), alloc_function(python__add, 1, "python__add"));
alloc_field(pyProto, val_id("__sub"), alloc_function(python__sub, 1, "python__sub"));
alloc_field(pyProto, val_id("__rsub"), alloc_function(python__sub, 1, "python__sub"));
alloc_field(pyProto, val_id("__mult"), alloc_function(python__mult, 1, "python__mult"));
alloc_field(pyProto, val_id("__rmult"), alloc_function(python__mult, 1, "python__mult"));
alloc_field(pyProto, val_id("__div"), alloc_function(python__div, 1, "python__div"));
alloc_field(pyProto, val_id("__rdiv"), alloc_function(python__div, 1, "python__div"));
alloc_field(pyProto, val_id("__mod"), alloc_function(python__mod, 1, "python__mod"));
alloc_field(pyProto, val_id("__rmod"), alloc_function(python__mod, 1, "python__mod"));
alloc_field(pyProto, val_id("__get"), alloc_function(python__get, 1, "python__get"));
alloc_field(pyProto, val_id("__set"), alloc_function(python__set, 2, "python__set"));
}

static value python_eval(value str) {
return python_run(str, true);
}

static value python_execute(value str) {
return python_run(str, false);
}

DEFINE_PRIM(python_eval, 1);
DEFINE_PRIM(python_execute, 1);
DEFINE_PRIM(python_globals, 0);
DEFINE_PRIM(python_locals, 0);

BOOL APIENTRY DllMain( HANDLE hModule, 
					  DWORD  ul_reason_for_call, 
					  LPVOID lpReserved
					  )
{
	return TRUE;
}
